﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NuMvvm.Messaging
{
    public sealed class Messenger : IMessenger
    {
        private readonly List<SubscriptionGroup> _subscriptionGroups = new List<SubscriptionGroup>();
        private static Messenger _default;

        internal class SubscriptionGroup
        {
            public SubscriptionGroup(Type messageType)
            {
                if(messageType == null)
			        throw new ArgumentNullException("messageType");

                MessageType = messageType;
                Subscriptions = new List<object>();
            }

            public Type MessageType { get; private set; }
            public List<object> Subscriptions { get; private set; }
        }

        public void Send<TMessage>(TMessage message)
        {
            var subscriptionGroup = _subscriptionGroups.First(x => x.MessageType == typeof(TMessage));
            foreach (var subscription in subscriptionGroup.Subscriptions)
            {
                var handler = (Action<TMessage>)subscription;
                handler(message);
            }
        }

        public void Subscribe<TMessage>(Action<TMessage> handler)
        {
            var subscriptionGroup = _subscriptionGroups.FirstOrDefault(x => x.MessageType == typeof(TMessage));
            if (subscriptionGroup == null)
            {
                subscriptionGroup = new SubscriptionGroup(typeof(TMessage));
                _subscriptionGroups.Add(subscriptionGroup);
            }

            subscriptionGroup.Subscriptions.Add(handler);
        }

        public void Unsubscribe<TMessage>(Action<TMessage> handler)
        {
            var subscriptionGroup = _subscriptionGroups
                .First(x => x.MessageType == typeof(TMessage));

            subscriptionGroup.Subscriptions.Remove(handler);
        }

        /// <summary>
        /// Gets the default Messenger.
        /// </summary>
        public static IMessenger Default
        {
            get
            {
                if (_default == null)
                {
                    _default = new Messenger();
                }
                return _default;
            }
        }
    }
}
